/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package service.posServices;

import com.openbrew.openbrewrf.POSLineItems;
import com.openbrew.openbrewrf.POSReceiptTbl;
import com.openbrew.openbrewrf.POSSale;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 *
 * @author dchapman
 */
@Stateless
@Path("com.openbrew.openbrewrf.posreconciliation")
public class POSReconciliationREST {
    @PersistenceContext(unitName = "com.openBrew_openBrewRF_war_1.0PU")
    private EntityManager em;
    
    public POSReconciliationREST() {
    }
    
    private List<POSSale> sales = new ArrayList<POSSale>();
    
    private final String STARLINE = "****************************************";
    private final String NL = "\n";
    private final int LENGTH = 40;
        
    private void loadUnreconciledSales(){
        sales.removeAll(sales);
        sales = getEntityManager().createNamedQuery("POSSale.findUnreconciledItems", POSSale.class).getResultList();
    }
    
    private void insertReceipt(final String rcpt, final Date date){
        POSReceiptTbl rTbl = new POSReceiptTbl();
        rTbl.setReceipt(rcpt);
        rTbl.setDate(date);
        getEntityManager().persist(rTbl);
    }
    
    private void updateSalesToReconciled(final List<POSSale> salesToUpdate){
        for(POSSale sale : salesToUpdate){
            sale.setReconciled(true);
            getEntityManager().merge(sale);
        }
    }
    
    private String getReceiptByDate(final Date date){
        TypedQuery<POSReceiptTbl> query = getEntityManager().createQuery(
                "SELECT r FROM POSReceiptTbl r WHERE r.date = ?1", POSReceiptTbl.class);
        query.setParameter(1, date, TemporalType.DATE);
        List<POSReceiptTbl> rcpts = query.getResultList();
        if(rcpts.size()>0){
            String result = rcpts.get(0).getReceipt();
            if(rcpts.size()>1){
                result += "\n\nNotice! This date contains " + Integer.toString(rcpts.size())
                        + " entities.\n"
                        + "The displayed reciept is the first\n"
                        + "receipt entered on that day. For\n"
                        + "more info use openBrew Application.";
            }
            return result;
        } 
        return "Receipt for given date does not exist!";
    }
    
    @GET
    @Path("WTFisTheDate")
    @Produces(MediaType.TEXT_PLAIN)
    public String find(){
        Date today = new Date();
        return today.toString();
    }
    
    @GET
    @Path("{date}/{taxRate}")
    @Produces(MediaType.TEXT_PLAIN)
    public String find(@PathParam("date") Date date
            , @PathParam("taxRate") double taxRate) {
        SimpleDateFormat formatter = new SimpleDateFormat("MM-dd-yyyy");
        //Load all unreconciled sales
        loadUnreconciledSales();
        //Setup calendar for run
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        final Date setDate = cal.getTime();
        
        //Setup variables used in string building.
        int ticketsNotClosedOut = 0;
        double totalCash = 0;
        double totalCredit = 0;
        double totalGiftCards = 0;
        double totalTabs = 0;
        double totalLoyalty = 0;
        double taxExempt = 0;
        
        List<POSSale> salesToUpdate = new ArrayList<POSSale>();
        
        for(POSSale sale : sales){
            if(sale.getTabPaidTime().before(setDate) || sale.getTabPaidTime().equals(setDate)){
                if(!sale.isSaleComplete()){
                    ticketsNotClosedOut++;
                } else {
                    if(sale.getSaleCash()>0){
                        totalCash += (double)sale.getSaleCash();
                    }
                    if(sale.getSaleCredit()>0){
                        totalCredit += (double)sale.getSaleCredit();
                    }
                    if(sale.getSaleGiftCard()>0){
                        totalGiftCards += (double)sale.getSaleGiftCard();
                    }
                    if(sale.getSaleOther()>0){
                        totalTabs += (double)sale.getSaleOther();
                    }
                    if(sale.getLoyaltyMoney()>0){
                        totalLoyalty += (double)sale.getLoyaltyMoney();
                    }
                    salesToUpdate.add(sale);
                    for(POSLineItems item : sale.getLineItemTypeCollection()){
                        if(item.getSupply()!=null && item.getSupply().isTaxExempt()){
                            if(item.getPriceOverRide()>0){
                                taxExempt += item.getPriceOverRide();
                            } else if(item.getDiscount()!=null){
                                if(item.getDiscount().getFlat()>0){
                                    taxExempt += (item.getSupply().getSupReSalePrice() 
                                            - item.getDiscount().getFlat());
                                } else if(item.getDiscount().getPct()>0){
                                    taxExempt += (item.getSupply().getSupReSalePrice()
                                            - (item.getSupply().getSupReSalePrice() 
                                            * (item.getDiscount().getPct()/100)));
                                }
                            } else {
                                taxExempt += item.getSupply().getSupReSalePrice();
                            }
                        }
                    }
                }
            }
        }
        
        Date today = new Date();
        final double totalMade = totalCash+totalCredit+totalGiftCards;
        double taxExemptToRemove = taxExempt*(taxRate/100);
        double netLessTax = (totalMade/(1+(taxRate/100))+taxExemptToRemove);
        
        String output = STARLINE + NL 
                + center("openBrewPOS Close Out - " + formatter.format(setDate), LENGTH) + NL
                + center("Printed: " + formatter.format(today), LENGTH) + NL
                + center(today.toString(), LENGTH) + NL
                + STARLINE + NL
                + list("Tickets Not Closed Out:", Integer.toString(ticketsNotClosedOut)) + NL + NL
                + list("Total Amount Collected:", "$" + String.format("%.2f", totalMade)) + NL
                + list("Total Cash Collected:", "$" + String.format("%.2f", totalCash)) + NL
                + list("Total Credit Collected:", "$" + String.format("%.2f", totalCredit)) + NL
                + list("Total GiftCards Collected:", "$" + String.format("%.2f", totalGiftCards)) + NL 
                + STARLINE + NL
                + list("Total Tab Loss:", "$" + String.format("%.2f", totalTabs)) + NL
                + list("Total Loylaty Loss:", "$" + String.format("%.2f", totalLoyalty)) + NL
                + list("Tax Rate:", Double.toString(taxRate) + "%") + NL
                + list("NET SALES LESS TAX:", "$" + String.format("%.2f", netLessTax)) + NL
                + list("TAX EXEMPT ITEMS:", "$" + String.format("%.2f", taxExempt)) + NL
                + list("Sales Tax Collected:", "$" + String.format("%.2f", totalMade - netLessTax));
        if(salesToUpdate.size()>0){
            //If there were valid items to report, update the sales items and insert receipt
            //into database.
            insertReceipt(output, today);
            updateSalesToReconciled(salesToUpdate);
        } else {
            //If this array is empty, then this report has already been run, find the appropriate
            //entity in the database receipt table and return that instead.
            output = "Archived Receipt Result:\n\n";
            output += getReceiptByDate(setDate);
        }
        
        return output;
    }
    
    private String center(String text, int len){
            String out = String.format("%"+len+"s%s%"+len+"s", "",text,"");
        float mid = (out.length()/2);
        float start = mid - (len/2);
        float end = start + len; 
        return out.substring((int)start, (int)end);
    }

    private String list(String textLeft, String textRight){
            return String.format("%-30s%10s", textLeft.substring(0, Math.min(textLeft.length(), 30)), textRight);
    }
    
    protected EntityManager getEntityManager() {
        return em;
    }
}
